#!/usr/bin/env python
#
# Copyright 2005,2006 Lukasz Strzygowski <lucass@gentoo.org>, Marcin Kurczych <tharkang@gmail.com> 
# Distributed under the terms of the GNU General Public License v2
#

"""
Solution tester
"""

from django.conf import settings
import sys
import os
from time import sleep
from subprocess import Popen,PIPE
from pacs.models import TestResults


#command to run saferun
saferunCommand = "saferun/sr -t %(maxTime)d -m %(maxMem)d -- %(executable)s"		

def run_test(testResults):
	"""Fills in test results"""

	#gets submission and test
	submission = testResults.submission
	test = testResults.test

	#get needed files paths
	executablePath = os.path.join(settings.EXECUTABLES_PATH,str(submission.id))
	testInPath = os.path.join(settings.TESTS_PATH,str(test.problem.id),"in",test.name)
	testOutPath = os.path.join(settings.TESTS_PATH,str(test.problem.id),"out",test.name)
	checkerPath = os.path.join(settings.TESTS_PATH,str(test.problem.id),"checker")
	outPath = os.path.join(settings.TESTS_PATH,str(test.problem.id),"pout",str(submission.id),test.name)
	print outPath

	#if no problem checker, uses default
	if not os.access(checkerPath,os.R_OK | os.X_OK):
		checkerPath = os.path.join(settings.TESTS_PATH,"checker")

	#checks if has needed permissions
	if not os.access(executablePath,os.R_OK | os.X_OK):
		testResults.status = 9
		testResults.comment = "cannot run executable"
		testResults.save()
		return
	elif not os.access(checkerPath,os.R_OK | os.X_OK):
		testResults.status = 9
		testResults.comment = "cannot run checker"
		testResults.save()
		return
	elif not os.access(testInPath,os.R_OK) or not os.access(testOutPath,os.R_OK):
		testResults.status = 9
		testResults.comment = "cannot open test"
		testResults.save()
		return
	#elif not os.access(outPath,os.W_OK):
	#	testResults.status = 9
	#	testResults.comment = "cannot open program output"
	#	testResults.save()
	#	return

	#opens input and output
	inp = open(testInPath,"r")
	out = open(outPath,"w")

	#runs code
	checkProc = Popen(saferunCommand%{'maxTime':test.maxTime,'maxMem':test.memLimit,'executable':executablePath}, shell=True, \
							stdin=inp, stdout=out, stderr=PIPE)
	#saferun info
	srOut = checkProc.stderr.read().split('\n')
	code = checkProc.wait()
	
	#time
	try:
		testResults.time = int(srOut[0].split()[0])
	except ValueError:
		testResults.comment="WO: "+srOut[0][4:60]
	else:
		if len(srOut) > 1:
			testResults.comment=srOut[1][4:68]
		else:
			testResults.comment="WTF?"

	if code != 0: #saferun bug
		testResults.status = 9
	elif srOut[1][:3] == "RCD": # Return Code
		testResults.status = 5
	elif srOut[1][:3] == "SCL": # Forbidden SigCall -> Rule Violation
		testResults.status = 7
	elif srOut[1][:3] == "SIG": # Ended with signal
		testResults.status = 6
	elif srOut[1][:3] != "ACC": # Unknown code
		testResults.status = 9
		testResults.comment = "WTF?:"+srOut[:60]
	else: # no errors - run checker
		print "%s %s %s %s"%(checkerPath,testInPath,testOutPath,outPath)
		verifyProc = Popen("%s %s %s %s"%(checkerPath,outPath,testOutPath,testInPath),shell=True,stdin=None,stdout=PIPE,stderr=None)
		#checker output
		out = verifyProc.stdout.read()
		verifyProc.wait()
		if not out: # no errors - ok
			testResults.status = 0
			testResults.comment = ""
		else: # wrong answer + info
			testResults.status = 2
			testResults.comment = out[:64]
	testResults.save()


if __name__ == '__main__':
	while True:
		for tr in TestResults.objects.filter(status=10,test__checkTime__isnull=False).order_by("pacs_testresults__test.checkTime"):
			run_test(tr)
		sleep(0.1)
